﻿
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using VOL.Core.CacheManager;
using VOL.Core.Configuration;
using VOL.Core.Controllers.Basic;
using VOL.Core.DBManager;
using VOL.Core.EFDbContext;
using VOL.Core.Enums;
using VOL.Core.Extensions;
using VOL.Core.Filters;
using VOL.Core.Infrastructure;
using VOL.Core.ManageUser;
using VOL.Core.ObjectActionValidator;
using VOL.Core.Services;
using VOL.Core.Utilities;
using VOL.Entity.AttributeManager;
using VOL.Entity.DomainModels;
using VOL.System.IRepositories;
using VOL.System.IServices;
using VOL.System.Repositories;

namespace VOL.System.Controllers
{
    [Route("api/User")]
    public partial class Sys_UserController
    {
        private ISys_UserRepository _userRepository;
        private IHttpClientFactory _httpClientFactory;
        private ICacheService _cache;
        [ActivatorUtilitiesConstructor]
        public Sys_UserController(
               ISys_UserService userService,
               ISys_UserRepository userRepository,
               ICacheService cahce,
                  IHttpClientFactory httpClientFactory
              )
          : base(userService)
        {
            _userRepository = userRepository;
            _cache = cahce;
            _httpClientFactory = httpClientFactory;
        }

        [HttpPost, HttpGet, Route("login"), AllowAnonymous]
        [ObjectModelValidatorFilter(ValidatorModel.Login)]
        public async Task<IActionResult> Login([FromBody] LoginInfo loginInfo)
        {
            return Json(await Service.Login(loginInfo));
        }

        private readonly ConcurrentDictionary<int, object> _lockCurrent = new ConcurrentDictionary<int, object>();
        [HttpPost, Route("replaceToken")]
        public IActionResult ReplaceToken()
        {
            WebResponseContent responseContent = new WebResponseContent();
            string error = "";
            string key = $"rp:Token:{UserContext.Current.UserId}";
            UserInfo userInfo = null;
            try
            {
                //如果5秒内替换过token,直接使用最新的token(防止一个页面多个并发请求同时替换token导致token错位)
                if (_cache.Exists(key))
                {
                    return Json(responseContent.OK(null, _cache.Get(key)));
                }
                var _obj = _lockCurrent.GetOrAdd(UserContext.Current.UserId, new object() { });
                lock (_obj)
                {
                    if (_cache.Exists(key))
                    {
                        return Json(responseContent.OK(null, _cache.Get(key)));
                    }
                    string requestToken = HttpContext.Request.Headers[AppSetting.TokenHeaderName];
                    requestToken = requestToken?.Replace("Bearer ", "");

                    if (JwtHelper.IsExp(requestToken)) return Json(responseContent.Error("Token已过期!"));

                    int userId = UserContext.Current.UserId;

                    userInfo = _userRepository.FindAsIQueryable(x => x.User_Id == userId).Select(
                             s => new UserInfo()
                             {
                                 User_Id = userId,
                                 UserName = s.UserName,
                                 UserTrueName = s.UserTrueName,
                                 Role_Id = s.Role_Id,
                                 RoleName = s.RoleName
                             }).FirstOrDefault();

                    if (userInfo == null) return Json(responseContent.Error("未查到用户信息!"));

                    string token = JwtHelper.IssueJwt(userInfo);
                    //移除当前缓存
                    _cache.Remove(userId.GetUserIdKey());
                    //只更新的token字段
                    _userRepository.Update(new Sys_User() { User_Id = userId, Token = token }, x => x.Token, true);
                    //添加一个5秒缓存
                    _cache.Add(key, token, 5);
                    responseContent.OK(null, token);
                }
            }
            catch (Exception ex)
            {
                error = ex.Message + ex.StackTrace;
                responseContent.Error("token替换异常");
            }
            finally
            {
                _lockCurrent.TryRemove(UserContext.Current.UserId, out object val);
                string _message = $"用户{userInfo?.User_Id}_{userInfo?.UserTrueName},({(responseContent.Status ? "token替换成功" : "token替换失败")})";
                Logger.Info(LoggerType.ReplaceToeken, _message, null, error);
            }
            return Json(responseContent);
        }


        [HttpPost, Route("modifyPwd")]
        [ApiActionPermission]
        //通过ObjectGeneralValidatorFilter校验参数，不再需要if esle判断OldPwd与NewPwd参数
        [ObjectGeneralValidatorFilter(ValidatorGeneral.OldPwd, ValidatorGeneral.NewPwd)]
        public async Task<IActionResult> ModifyPwd(string oldPwd, string newPwd)
        {
            return Json(await Service.ModifyPwd(oldPwd, newPwd));
        }

        [HttpPost, Route("getCurrentUserInfo")]
        public async Task<IActionResult> GetCurrentUserInfo()
        {
            return Json(await Service.GetCurrentUserInfo());
        }

        //只能超级管理员才能修改密码
        //2020.08.01增加修改密码功能
        [HttpPost, Route("modifyUserPwd"), ApiActionPermission(ActionRolePermission.SuperAdmin)]
        public IActionResult ModifyUserPwd(string password, string userName)
        {
            WebResponseContent webResponse = new WebResponseContent();
            if (string.IsNullOrEmpty(password) || string.IsNullOrEmpty(userName))
            {
                return Json(webResponse.Error("参数不完整"));
            }
            if (password.Length < 6) return Json(webResponse.Error("密码长度不能少于6位"));

            ISys_UserRepository repository = Sys_UserRepository.Instance;
            Sys_User user = repository.FindFirst(x => x.UserName == userName);
            if (user == null)
            {
                return Json(webResponse.Error("用户不存在"));
            }
            user.UserPwd = password.EncryptDES(AppSetting.Secret.User);
            repository.Update(user, x => new { x.UserPwd }, true);
            //如果用户在线，强制下线
            UserContext.Current.LogOut(user.User_Id);
            return Json(webResponse.OK("密码修改成功"));
        }

        /// <summary>
        /// 2020.06.15增加登陆验证码
        /// </summary>
        /// <returns></returns>
        [HttpGet, Route("getVierificationCode"), AllowAnonymous]
        public IActionResult GetVierificationCode()
        {
            string code = VierificationCode.RandomText();
            var data = new
            {
                img = VierificationCode.CreateBase64Imgage(code),
                uuid = Guid.NewGuid()
            };
            HttpContext.GetService<IMemoryCache>().Set(data.uuid.ToString(), code, new TimeSpan(0, 5, 0));
            return Json(data);
        }



        [HttpGet, Route("getUserName")]
        public IActionResult GetUserName()
        {
            return Json(new { userName = UserContext.Current.UserTrueName, date = DateTime.Now });
        }
        /// <summary>
        /// 绑定微信
        /// </summary>
        /// <returns></returns>
        [HttpPost, Route("binWeChat")]
        public async Task<IActionResult> BindWeChat([FromBody] LoginWeChatInfo loginWeChat)
        {
            return await GetWeChatUserInfo(loginWeChat, true);
        }

        /// <summary>
        /// 微信小程序登陆
        /// </summary>
        /// <returns></returns>
        [HttpPost, Route("loginWeChat"), AllowAnonymous]
        public async Task<IActionResult> LoginWeChat([FromBody] LoginWeChatInfo loginWeChat)
        {
            return await GetWeChatUserInfo(loginWeChat);
        }

        private async Task<IActionResult> GetWeChatUserInfo(LoginWeChatInfo loginWeChat, bool binWeChat = false)
        {
            WebResponseContent webResponse = new WebResponseContent();

            if (loginWeChat == null)
            {
                return Json(webResponse.Error($"参数不完整"));
            }

            string appid = AppSetting.GetSection("WeChat")["appid"];
            string secret = AppSetting.GetSection("WeChat")["secret"];

            string url = $"https://api.weixin.qq.com/sns/jscode2session?appid={appid}&secret={secret}&js_code={loginWeChat.Code}&grant_type=authorization_code";

            //获取sessionkey
            (bool status, SesstionResult result, string message) data = await _httpClientFactory.GetAsync<SesstionResult>(url);

            if (!data.status || data.result == null || string.IsNullOrEmpty(data.result.Openid))
            {
                Logger.Info($"授权失败:{data.Serialize()}");
                return Json(webResponse.Error($"授权失败:{data.message}"));
            }
            Sys_User user = null;
            if (binWeChat)
            {
                user = _userRepository.FindAsIQueryable(c => c.User_Id == UserContext.Current.UserId).FirstOrDefault();
                //if (user!=null)
                //{
                //    return Json(webResponse.Error($"已经绑定过微信,不能重复绑定"));
                //}
                //绑定微信
                user.OpenId = data.result.Openid;
                _userRepository.Update(user, x => new { x.OpenId }, true);
                return Json(webResponse.OK($"绑定成功"));
            }

            user = _userRepository.FindAsIQueryable(c => c.OpenId == data.result.Openid).FirstOrDefault();
            //帐号还未绑定微信
            if (user == null)
            {
                return Json(new { status = false, message = "微信还没未绑定账号,请在个人中心绑定账号" });
            }

            //获取用户名称与头像城市等
            var wxUserInfo = DEncryptedData(loginWeChat.EncryptedData, data.result.Session_Key, loginWeChat.IV);
            // wxUserInfo.
            //返回登陆信息
            var userInfo = new UserInfo()
            {
                User_Id = user.User_Id,
                UserName = user.UserName,
                Role_Id = user.Role_Id
            };
            string token = JwtHelper.IssueJwt(userInfo);
            user.Token = token;
            _userRepository.Update(user, x => x.Token, true);
            return Json(webResponse.OK("登录成功", new
            {
                token,
                userName = user.UserTrueName,
                img = user.HeadImageUrl
            }));
        }


        private WeChatUserInfo DEncryptedData(string encryptedData, string session_Key, string iv)
        {
            byte[] encryptedDatas = Convert.FromBase64String(encryptedData);

            using (RijndaelManaged rijndaelCipher = new RijndaelManaged())
            {
                rijndaelCipher.Key = Convert.FromBase64String(session_Key); // Encoding.UTF8.GetBytes(AesKey);
                rijndaelCipher.IV = Convert.FromBase64String(iv);// Encoding.UTF8.GetBytes(AesIV);
                rijndaelCipher.Mode = CipherMode.CBC;
                rijndaelCipher.Padding = PaddingMode.PKCS7;
                using (ICryptoTransform transform = rijndaelCipher.CreateDecryptor())
                {
                    byte[] plainText = transform.TransformFinalBlock(encryptedDatas, 0, encryptedDatas.Length);
                    string text = Encoding.Default.GetString(plainText);
                    Logger.Info($"小程序获取用户信息:{text}");
                    var wxUserInfo = text.DeserializeObject<WeChatUserInfo>();
                    return wxUserInfo;
                }
            }
        }
    }

    public class SesstionResult
    {
        public string Session_Key { get; set; }
        public string Openid { get; set; }
        public string Token { get; set; }
        public bool IsAuth { get; set; }

        public string Access_Token { get; set; }
    }

    public class LoginWeChatInfo
    {
        public string Code { get; set; }
        /// <summary>
        /// OpenId
        /// </summary>
        public string OpenId { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string IV { get; set; }
        /// <summary>
        /// 加密数据
        /// </summary>
        public string EncryptedData { get; set; }
    }


    /// <summary>
    /// 微信用户信息
    /// </summary>
    public class WeChatUserInfo
    {
        /// <summary>
        /// 昵称
        /// </summary>
        public string NickName { get; set; }
        /// <summary>
        /// 性别
        /// </summary>
        public string Gender { get; set; }
        /// <summary>
        /// 省份
        /// </summary>
        public string Province { get; set; }
        /// <summary>
        /// 城市
        /// </summary>
        public string City { get; set; }
        /// <summary>
        /// 国家
        /// </summary>
        public string Country { get; set; }

        /// <summary>
        /// 国家
        /// </summary>
        public string CountryCode { get; set; }
        /// <summary>
        /// 头像
        /// </summary>
        public string AvatarUrl { get; set; }
        public Watermark Watermark;
    }

    public class Watermark
    {
        public long Timestamp { get; set; }
        public string Appid { get; set; }
    }
}
